package com.jphotomanager.io;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.ExifThumbnailDirectory;
import com.mortennobel.imagescaling.ResampleOp;
import com.openroom.db.DBHelper;
import com.openroom.event.ApplicationEvent;
import com.openroom.event.EventManager;
import com.openroom.event.EventType;
import com.openroom.model.Catalog;
import com.openroom.model.Folder;
import com.openroom.model.ModelLocator;
import com.openroom.model.Photograph;
import com.openroom.ui.SupportedFileFilter;

public class ImageImporter {

	private static final Logger LOGGER = Logger.getLogger(ImageImporter.class);

	public static final int PREVIEW_HEIGHT = 800;
	public static final int PREVIEW_WIDTH = 1280;
	public static final int THUMBNAIL_HEIGHT = 120;
	public static final int THUMBNAIL_WIDTH = 160;
	private static SupportedFileFilter filefilter = new SupportedFileFilter();

	public static File saveEditedImage(BufferedImage image,
			Photograph photograph) {
		try {
			String previewImagePath = photograph.getRawFilePath();
			File file = new File(previewImagePath);
			String string = UUID.randomUUID().toString();
			String fileName = RawConverter
					.getFilenameWithoutExtension(photograph.getFileName());
			File file2 = new File(file.getParent(), fileName + "_" + string
					+ ".jpg");
			ImageIO.write(image, "JPG", file2);
			return file2;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void deleteAllRejected() {
		Folder folder = ModelLocator.getInstance().getCurrentlySelectedFolder();
		List<Photograph> allPhotographsOfFolder = DBHelper.getInstance()
				.getAllPhotographsOfFolder(folder.getFolderId(), true);
		for (Photograph photograph : allPhotographsOfFolder) {
			if (photograph.isRejected()) {
				String thumbnailPath = photograph.getThumbnailPath();
				FileUtils.deleteQuietly(new File(thumbnailPath));
				String previewPath = photograph.getPreviewImagePath();
				if (previewPath != null)
					FileUtils.deleteQuietly(new File(previewPath));
				String rawFilePath = photograph.getRawFilePath();
				if (rawFilePath != null)
					FileUtils.deleteQuietly(new File(rawFilePath));
				DBHelper.getInstance().deleteImage(photograph.getPhotoId());
			}
		}
	}

	public static List<Photograph> importImages(File directory,
			boolean recursive, String dirPath) {
		List<Photograph> files = new ArrayList<Photograph>();
		if (directory.isDirectory()) {
			File[] listFiles = directory.listFiles();
			for (File file : listFiles) {
				if (file.isFile() && filefilter.accept(file)) {
					Photograph p = importFile(dirPath, file);
					files.add(p);
				} else if (file.isDirectory()) {
					List<Photograph> listImages = importImages(file, true,
							dirPath);
					files.addAll(listImages);
				}
			}
		}
		return files;
	}

	public static Photograph importFile(String dirPath, File file) {
		Photograph p = new Photograph();
		p.setOriginalPath(file.getAbsolutePath());
		p.setFileName(file.getName());
		try {
			Metadata metadata = ImageMetadataReader.readMetadata(file);
			ExifThumbnailDirectory dir = metadata
					.getOrCreateDirectory(ExifThumbnailDirectory.class);
			ExifSubIFDDirectory exif = metadata
					.getOrCreateDirectory(ExifSubIFDDirectory.class);
			String date = exif
					.getString(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
			LOGGER.debug("got " + date + " from EXIF");
			byte[] thumbnailData = dir.getThumbnailData();
			Catalog catalog = null;
			if (thumbnailData != null) {
				if (date != null) {
					catalog = DBHelper.getInstance().getOrCreateCatalog(date);
					EventManager.getInstance()
							.publishEvent(
									new ApplicationEvent(
											EventType.ALL_CATALOG_CHANGED));
					File folderFromDate = getFolderFromDate(date, dirPath);
					File thumbnailImage = new File(folderFromDate,
							RawConverter.getFilenameForThumbnail(file));
					p.setThumbnailPath(thumbnailImage.getAbsolutePath());
					if (!thumbnailImage.exists()) {
						LOGGER.debug("Writing thumbnail to " + folderFromDate);
						FileUtils.writeByteArrayToFile(thumbnailImage,
								thumbnailData);
					}
					File originalCopy = new File(folderFromDate, file.getName());
					FileUtils.copyFile(file, originalCopy);
					p.setRawFilePath(originalCopy.getAbsolutePath());
				} else {
					System.err.println("Unable to import " + file);
				}
			} else {
				long lastModified = file.lastModified();
				Date date2 = new Date(lastModified);
				File folderFromDate = getFolderFromDate(dirPath, date2);
				catalog = DBHelper.getInstance().getOrCreateCatalog(date2);
				EventManager.getInstance().publishEvent(
						new ApplicationEvent(EventType.ALL_CATALOG_CHANGED));
				File thumbnailImage = new File(folderFromDate,
						RawConverter.getFilenameForThumbnail(file));
				BufferedImage read = ImageIO.read(file);
				if (read == null) {
					throw new RuntimeException("Can not read image "
							+ file.getAbsolutePath());
				}
				createScaledImage(thumbnailImage, read, THUMBNAIL_WIDTH,
						THUMBNAIL_HEIGHT);
				File previewImage = new File(folderFromDate,
						RawConverter.getFilenameForPreviewJPG(file));
				createScaledImage(previewImage, read, PREVIEW_WIDTH,
						PREVIEW_HEIGHT);
				File originalCopy = new File(folderFromDate, file.getName());
				FileUtils.copyFile(file, originalCopy);
				p.setRawFilePath(originalCopy.getPath());
				p.setPreviewImagePath(new File(folderFromDate, RawConverter
						.getFilenameForPreviewJPG(file)).getAbsolutePath());
				p.setThumbnailPath(thumbnailImage.getAbsolutePath());

			}
			Folder folder = DBHelper.getInstance().getOrCreateFolder(
					file.getParent());
			p.setFolderId(folder.getFolderId());
			DBHelper.getInstance().savePhotographs(p);
			DBHelper.getInstance().saveCatalogAssociation(catalog, p);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return p;
	}

	public static void createPreviewImageForViewedItems(Photograph photograph,
			BufferedImage read) {
		try {
			String parent = new File(photograph.getThumbnailPath()).getParent();
			File rawFile = new File(photograph.getRawFilePath());
			File previewImage = new File(parent,
					RawConverter.getFilenameForPreviewJPG(rawFile));

			if (isRawFile(rawFile) && !RawConverter.isRawFileSupported()) {
			    if (RawConverter.isSupportedRawFile(rawFile)) {
                    File jpegFile = RawConverter.extractJpeg(rawFile);
                    if (jpegFile != null) {
                        rawFile = jpegFile;
                    } else
                        return;
                } else
                    return;
			}
			if (!previewImage.exists())
				createScaledImage(previewImage, read, PREVIEW_WIDTH,
						PREVIEW_HEIGHT);
			LOGGER.info("Creating thumbnail for " + photograph.getFileName()
					+ " at " + previewImage.getAbsolutePath());
			ModelLocator.getInstance().updatePreviewPath(
					photograph.getPhotoId(), previewImage.getAbsolutePath());
			DBHelper.getInstance().updatePreviewPath(photograph.getPhotoId(),
					previewImage.getAbsolutePath());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void createScaledImage(File destImageFile,
			BufferedImage read, int maxWidth, int maxHeight) throws IOException {
		if (destImageFile.exists())
			return;
		int origWidth = read.getWidth();
		int origHeight = read.getHeight();
		float aspectRatio = ((float) origWidth / origHeight);
		int scaledWidth = origWidth;
		int scaledHeight = origHeight;
		if (aspectRatio < 1) {
			scaledHeight = maxHeight;
			scaledWidth = (int) (aspectRatio * maxHeight);
		} else {
			scaledWidth = maxWidth;
			scaledHeight = (int) (maxWidth / aspectRatio);
		}
		ResampleOp resampleOp = new ResampleOp(scaledWidth, scaledHeight);
		BufferedImage rescaledTomato = resampleOp.filter(read, null);
		ImageIO.write(rescaledTomato, "JPG", destImageFile);
	}

	public static boolean isRawFile(File file) {
		if (file.getName().toUpperCase().endsWith(".CR2")
				|| file.getName().toUpperCase().endsWith(".NEF")) {
			return true;
		}
		return false;
	}

	public static File getFolderFromDate(String date, String dirPath)
			throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
		Date parse = format.parse(date);
		return getFolderFromDate(dirPath, parse);
	}

	private static File getFolderFromDate(String dirPath, Date parse) {
		SimpleDateFormat folderFormat = new SimpleDateFormat("yyyy/MM/dd");
		String format2 = folderFormat.format(parse);
		File file = new File(dirPath + "/" + format2);
		if (!file.exists()) {
			file.mkdirs();
		}
		return file;
	}
}
